#include "GraphicsWrapper.h"
#include "GraphicsException.h"
#include "TextureCache.h"
#include "SDL2/SDL_ttf.h"

static SDL_Window* screen = NULL;
static SDL_Renderer* renderer = NULL;

GraphicsWrapper::GraphicsWrapper()
{
}

GraphicsWrapper::~GraphicsWrapper()
{
}

void GraphicsWrapper::init()
{
    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();
}

void GraphicsWrapper::quit()
{
    TextureCache::clear();
    TTF_Quit();
    SDL_Quit();
}

Texture* GraphicsWrapper::createTexture(SDL_Surface* surface, int alpha)
{
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_SetTextureAlphaMod(texture, alpha);
    Size size(surface->w, surface->h);
    free(surface);
    return new Texture(texture, size);
}

void GraphicsWrapper::put(SDL_Texture* texture, const Area& area)
{
    SDL_Rect rect = { area.position.x, area.position.y, area.size.width, area.size.height };
    SDL_RenderCopy(renderer, texture, NULL, &rect);
}

void GraphicsWrapper::openWindow(int width, int height)
{
    screen = SDL_CreateWindow("RPG", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height,
            SDL_WINDOW_RESIZABLE);
    renderer = SDL_CreateRenderer(screen, -1, 0);

    if (screen == NULL)
    {
        throw GraphicsException("Error opening window");
    }
}

void GraphicsWrapper::clear()
{
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
    SDL_RenderClear(renderer);
}

void GraphicsWrapper::flip()
{
    SDL_RenderPresent(renderer);
}

SDL_Surface* GraphicsWrapper::fillRectSurface(const Size& size, const Color& color)
{
    SDL_Surface* surface = SDL_CreateRGBSurface(0, size.width, size.height, 32, 0xff000000, 0x00ff0000, 0x0000ff00,
            0x000000ff);
    SDL_Rect rect = { 0, 0, size.width, size.height };
    SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, color.r, color.g, color.b));
    return surface;
}

Texture* GraphicsWrapper::fillRectCached(const Size& size, const Color& color)
{
    std::string key = "Rect" + TextureCache::keySizeColor(size) + TextureCache::keyFromColor(color);
    if (TextureCache::has(key))
    {
        return TextureCache::get(key);
    }
    Texture* texture = createTexture(fillRectSurface(size, color), color.a);
    TextureCache::put(key, texture);
    return texture;
}

Texture* GraphicsWrapper::createText(std::string text, unsigned int fontSize, const Color& color)
{
    TTF_Font* font = TTF_OpenFont("resources/optima.ttf", fontSize);
    SDL_Color sdlColor = { color.r, color.g, color.b, 0 };
    SDL_Surface* surface = TTF_RenderText_Blended(font, text.c_str(), sdlColor);
    TTF_CloseFont(font);
    return createTexture(surface, color.a);
}

void GraphicsWrapper::free(SDL_Surface* surface)
{
    SDL_FreeSurface(surface);
    surface = NULL;
}

Texture* GraphicsWrapper::loadImageCached(std::string path, int alpha)
{
    std::string key = "Image" + path;
    if (TextureCache::has(key))
    {
        return TextureCache::get(key);
    }
    Texture* texture = createTexture(SDL_LoadBMP(path.c_str()), alpha);
    TextureCache::put(key, texture);
    return texture;
}

